package com.kinglumi.ailighting.auth.service.biz;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.kinglumi.ailighting.auth.base.BaseService;
import com.kinglumi.ailighting.auth.base.Query;
import com.kinglumi.ailighting.auth.bo.ApiResult;
import com.kinglumi.ailighting.auth.constant.CommonConstant;
import com.kinglumi.ailighting.auth.constant.ServiceErrorEnum;
import com.kinglumi.ailighting.auth.dto.MeshAndUserInfoDTO;
import com.kinglumi.ailighting.auth.entity.*;
import com.kinglumi.ailighting.auth.exception.BaseBusinessException;
import com.kinglumi.ailighting.auth.mapper.MeshGroupMapper;
import com.kinglumi.ailighting.auth.mapper.MeshInfoMapper;
import com.kinglumi.ailighting.auth.mapper.MeshUserLinkMapper;
import com.kinglumi.ailighting.auth.mapper.UserMapper;
import com.kinglumi.ailighting.auth.redis.IRedisCache;
import com.kinglumi.ailighting.auth.util.DesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lee
 * @date 2021/9/1110:36
 */
@Service
@Slf4j
public class MeshInfoService extends BaseService<MeshInfoMapper, MeshInfo> {

    @Resource
    private MeshUserLinkMapper meshUserLinkMapper;

    @Resource
    private UserMapper userMapper;

    @Autowired
    private IRedisCache redisCache;

    @Resource
    private MeshGroupMapper meshGroupMapper;

    /**
     * 加入mesh
     *
     * @param invitationCode
     */
    public int joinMesh(String invitationCode) {
        String meshId = null;
        try {
            int i = DesUtil.base10(invitationCode);
            meshId = DesUtil.getMeshId(String.valueOf(i));
        } catch (Exception e) {
            throw new BaseBusinessException(ServiceErrorEnum.JOIN_MESH_FORMAT);
        }
        String redisCode = (String) redisCache.get(CommonConstant.RedisKeys.INVITATION_CODE + meshId);
        if (Objects.isNull(redisCode)) {
            log.error("当前meshId不存在：" + CommonConstant.RedisKeys.INVITATION_CODE + meshId);
            throw new BaseBusinessException(ServiceErrorEnum.JOIN_MESH_EXPIRED);
        }
        if (!redisCode.equals(invitationCode)) {
            throw new BaseBusinessException(ServiceErrorEnum.JOIN_MESH_INCORRECT);
        }
        Integer loginUserId = getLoginUserId();
        MeshUserLink link = new MeshUserLink();
        link.setMeshId(Integer.valueOf(meshId));
        link.setUserId(loginUserId);
        MeshUserLink meshUserLink = this.meshUserLinkMapper.selectOne(link);
        if (Objects.nonNull(meshUserLink)) {
            throw new BaseBusinessException(ServiceErrorEnum.JOIN_MESH_ALREADY);
        }
        return this.meshUserLinkMapper.insertUseGeneratedKeys(new MeshUserLink(Integer.valueOf(meshId), loginUserId));
    }

    /**
     * 管理员生成邀请码
     *
     * @param meshId meshID
     * @return
     */
    public String generateInvitationCode(Integer meshId) {
        // 修改mesh 只能是 管理员
        Integer userId = getLoginUserId();
        MeshInfo meshInfo = super.selectById(meshId);
//        if (Objects.isNull(meshInfo) || !userId.equals(meshInfo.getAdminId())) {
//            throw new BaseBusinessException(ServiceErrorEnum.MESH_NOT_ADMINISTRATOR);
//        }
//        Object redisCode = redisCache.get(CommonConstant.RedisKeys.INVITATION_CODE + meshInfo.getId());
//        if (Objects.nonNull(redisCode)) {
////            throw new BaseBusinessException(ServiceErrorEnum.JOIN_MESH_INVITATION_NOT_EXPIRED);
////            throw new BaseException("对不起，当前邀请码还未过期");
//            return (String) redisCode;
//        }
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            code.append(new Random().nextInt(9) + 1);
        }
        StringBuilder buffer = new StringBuilder();
        StringBuilder invitationCode = buffer.append(meshInfo.getId()).append(0).append(code);
        String s = invitationCode.toString();
        // 加密
        String base34 = DesUtil.base34(Integer.valueOf(s));
        // 三天后过期
        if(redisCache.setIfAbsent(CommonConstant.RedisKeys.INVITATION_CODE + meshInfo.getId(), base34, Duration.ofDays(3))){
            log.error("当前meshId保存得：" + CommonConstant.RedisKeys.INVITATION_CODE + meshInfo.getId());
        }else{
            //说明redis还存在，刷新meshId时间
            redisCache.set(CommonConstant.RedisKeys.INVITATION_CODE + meshInfo.getId(), base34, 259200);
        }
        return base34;
    }

    /**
     * 用户新增mesh 网络
     * 1.在用户-mesh关联表中 添加 关联
     *
     * @param entity
     */
    @Override
    public void insertSelective(MeshInfo entity) {
        UserInfo loginUser = getLoginUser();

        // 设置 管理员id
        entity.setAdminId(loginUser.getId());
        entity.setUserName(loginUser.getUsername());
        entity.setNickname(loginUser.getNickname());
        int meshId = super.insertSelectiveId(entity);
        this.meshUserLinkMapper.insertSelective(new MeshUserLink(meshId, loginUser.getId()));
    }

    @Override
    public int insertSelectiveId(MeshInfo entity) {
        UserInfo loginUser = getLoginUser();

        // 设置 管理员id
        entity.setAdminId(loginUser.getId());
        entity.setUserName(loginUser.getUsername());
        entity.setNickname(loginUser.getNickname());
        int meshId = super.insertSelectiveId(entity);
        this.meshUserLinkMapper.insertSelective(new MeshUserLink(meshId, loginUser.getId()));
        return meshId;
    }

    @Override
    public void updateSelectiveById(MeshInfo entity) {
        // 修改mesh 只能是 管理员
//        Integer userId = getLoginUserId();
//        MeshInfo meshInfo = super.selectById(entity.getId());
//        if (Objects.isNull(meshInfo) || !userId.equals(meshInfo.getAdminId())) {
//            throw new BaseBusinessException(ServiceErrorEnum.MESH_NOT_ADMINISTRATOR);
//        }
        super.updateSelectiveById(entity);
    }

    @Override
    public void deleteById(Object id) {
        Integer userId = getLoginUserId();
        MeshInfo meshInfo = super.selectById(id);
        if (Objects.isNull(meshInfo) || !userId.equals(meshInfo.getAdminId())) {
            throw new BaseBusinessException(ServiceErrorEnum.MESH_NOT_ADMINISTRATOR);
        }
        super.deleteById(id);
        List<MeshUserLink> meshUserLinks = this.meshUserLinkMapper.select(new MeshUserLink(meshInfo.getId()));
        List<Integer> list = meshUserLinks.stream().map(MeshUserLink::getId).collect(Collectors.toList());
        for (Integer integer : list) {
            this.meshUserLinkMapper.deleteByPrimaryKey(integer);
        }

    }

    /**
     * 新增成员
     *
     * @param meshId
     * @param userId
     */
    public void addMeshUserLink(Integer meshId, Integer userId) {
        Integer adminId = getLoginUserId();
        MeshInfo meshInfo = super.selectById(meshId);
        if (Objects.isNull(meshInfo) || !adminId.equals(meshInfo.getAdminId())) {
            throw new BaseBusinessException(ServiceErrorEnum.MESH_NOT_ADMINISTRATOR);
        }
        MeshUserLink link = new MeshUserLink();
        link.setMeshId(meshId);
        link.setUserId(userId);
        MeshUserLink meshUserLink = this.meshUserLinkMapper.selectOne(link);
        if (Objects.nonNull(meshUserLink)) {
            throw new BaseBusinessException(ServiceErrorEnum.MESH_NOT_ADMINISTRATOR);
        }
        this.meshUserLinkMapper.insertSelective(new MeshUserLink(meshId, userId));
    }

    /**
     * 获取登录用户Id
     *
     * @return 用户Id
     */
    private UserInfo getLoginUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserDetail principal = (UserDetail) authentication.getPrincipal();
        return principal.getUserInfo();
    }

    /**
     * 获取登录用户Id
     *
     * @return 用户Id
     */
    private Integer getLoginUserId() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserDetail principal = (UserDetail) authentication.getPrincipal();
        return principal.getUserInfo().getId();
    }

    public void deleteMeshUserLink(Integer meshId, Integer userId) {
        Integer adminId = getLoginUserId();
        MeshInfo meshInfo = super.selectById(meshId);
        if (Objects.isNull(meshInfo) || !adminId.equals(meshInfo.getAdminId())) {
            throw new BaseBusinessException(ServiceErrorEnum.MESH_NOT_ADMINISTRATOR);
        }
        MeshUserLink link = new MeshUserLink();
        link.setMeshId(meshId);
        link.setUserId(userId);
        MeshUserLink meshUserLink = this.meshUserLinkMapper.selectOne(link);
        if (Objects.isNull(meshUserLink)) {
            throw new BaseBusinessException(ServiceErrorEnum.MESH_NOT_MEMBER);
        }
        this.meshUserLinkMapper.delete(link);
    }

    /**
     * 查询当前用户的所有mesh
     *
     * @param adminId
     * @return
     */
    public Map<String, List<MeshInfo>> getUserAllMesh(Integer adminId) {
        if (Objects.isNull(adminId)) {
            adminId = getLoginUserId();
        }
        List<MeshInfo> meshInfos = this.selectList(new MeshInfo(adminId));
        MeshUserLink link = new MeshUserLink();
        link.setUserId(adminId);
        List<MeshUserLink> select = this.meshUserLinkMapper.select(link);
        Map<String, List<MeshInfo>> map = Maps.newHashMap();
        map.put("admin", meshInfos);
        if (!CollectionUtils.isEmpty(select)) {
            // 参与管理的去处重复的 管理员身份的
            List<Integer> list = select.stream().map(MeshUserLink::getMeshId).collect(Collectors.toList());
            List<Integer> tmp = Lists.newArrayList(list);
            if (!CollectionUtils.isEmpty(meshInfos)) {
                List<Integer> adminIds = meshInfos.stream().map(MeshInfo::getId).collect(Collectors.toList());
                for (Integer id : adminIds) {
                    if (list.contains(id)) {
                        tmp.remove(id);
                    }
                }
            }
            if (!CollectionUtils.isEmpty(tmp)) {
                List<MeshInfo> infos = this.selectByIds(StringUtils.join(tmp, ","));
                map.put("participant", infos);
            } else {
                map.put("participant", Lists.newArrayList());
            }
        }
        return map;
    }

    public Map<String, List<MeshInfo>> getUserAllMeshNew(Integer adminId) {
        if (Objects.isNull(adminId)) {
            adminId = getLoginUserId();
        }
        Map<String, List<MeshInfo>> map = Maps.newHashMap();
        List<MeshInfo> meshInfos = this.mapper.selectAllByUserId(adminId);
        List<MeshInfo> adminList = new ArrayList<>();
        List<MeshInfo> NoAdminList = new ArrayList<>();
        Integer finalAdminId = adminId;
        meshInfos.forEach(info -> {
            if(info.getAdminId().equals(finalAdminId)){
                adminList.add(info);
            }else{
                NoAdminList.add(info);
            }
        });
        map.put("admin", adminList);
        map.put("participant", NoAdminList);
        return map;
    }

    /**
     * 查询当前mesh的所有用户参与者
     *
     * @param meshId
     * @return
     */
    public List<UserInfo> getMeshAllUser(Integer meshId) {
        MeshUserLink link = new MeshUserLink();
        link.setMeshId(meshId);
        List<MeshUserLink> select = this.meshUserLinkMapper.select(link);
        if (CollectionUtils.isEmpty(select)) {
            return Lists.newArrayList();
        }
        List<Integer> userIds = select.stream().map(MeshUserLink::getUserId).collect(Collectors.toList());
        List<UserInfo> userInfos = this.userMapper.selectByIds(StringUtils.join(userIds, ","));
        userInfos.sort(Comparator.comparing(UserInfo::getCreateTime));
        return userInfos;
    }

    /**
     * 删除 是查询 用户信息
     *
     * @param userId
     * @return
     */
    public Object meshAndUserInfo(Integer userId) {

        Map<String, List<MeshInfo>> userAllMesh = getUserAllMesh(userId);

        if (Objects.isNull(userAllMesh)) {
            return null;
        }
        // 身为管理员 数目
        int adminNum = 0;
        // 参数数目
        int participantNum = 0;
        //总数
        int meshCountNum = 0;
        List<MeshInfo> admins = userAllMesh.get("admin");
        adminNum = CollectionUtils.isEmpty(admins) ? 0 : admins.size();

        List<MeshInfo> participants = userAllMesh.get("participant");
        participantNum = CollectionUtils.isEmpty(participants) ? 0 : participants.size();
        meshCountNum = adminNum + participantNum;

        UserInfo userInfo = this.userMapper.selectByPrimaryKey(userId);
        MeshAndUserInfoDTO userInfoDTO = new MeshAndUserInfoDTO();
        userInfoDTO.setUserInfo(userInfo);
        userInfoDTO.setMeshCountNum(meshCountNum);
        userInfoDTO.setAdminNum(adminNum);
        userInfoDTO.setParticipantNum(participantNum);
        return userInfoDTO;
    }

    /**
     * @param meshId
     */
    public void dissolution(Integer meshId) {
        if (Objects.isNull(meshId)) {
            throw new BaseBusinessException(ServiceErrorEnum.PARAMETER_IS_EMPTY);
        }
        UserInfo loginUser = getLoginUser();
        Boolean isAdmin = loginUser.getIsAdmin();
        if (!isAdmin) {
            throw new BaseBusinessException(ServiceErrorEnum.NOT_ADMIN);
        }
        // 先删除 关联mesh
        meshUserLinkMapper.deleteByMeshId(meshId);
        // 删除管理的 组
        meshGroupMapper.deleteByMeshId(meshId);
//        // 删除管理的 mesh
        this.mapper.deleteByMeshId(meshId);
    }

    @Override
    public ApiResult selectPageByQuery(Query query) {
        Page<Object> result = PageHelper.startPage(query.getPage(), query.getLimit());
        List<MeshInfo> meshInfos = this.mapper.selectByExample(this.query2example(query, false));
        if (CollectionUtils.isEmpty(meshInfos)) {
            return ApiResult.okPage();
        }

        for (MeshInfo meshInfo : meshInfos) {

            MeshUserLink meshUserLink = new MeshUserLink();
            meshUserLink.setMeshId(meshInfo.getId());
            List<MeshUserLink> userLinks = meshUserLinkMapper.select(meshUserLink);


            Set<Integer> userIds = userLinks.stream().map(MeshUserLink::getUserId).collect(Collectors.toSet());
            // 去除管理员信息
            userIds.remove(meshInfo.getAdminId());

            MeshGroup meshGroup = new MeshGroup();
            meshGroup.setMeshId(meshInfo.getId());
            List<MeshGroup> meshGroups = meshGroupMapper.select(meshGroup);

            if(!CollectionUtils.isEmpty(userIds)){
                meshInfo.setMemberNum(userIds.size());
            }

            if(!CollectionUtils.isEmpty(meshGroups)){
                meshInfo.setGroupNum(meshGroups.size());
            }

            if (!CollectionUtils.isEmpty(userIds)) {
                List<UserInfo> userInfos = userMapper.selectByIds(StringUtils.join(userIds, ","));

                meshInfo.setUserInfoList(userInfos);
            } else {
                meshInfo.setUserInfoList(Lists.newArrayList());
            }
        }

        return ApiResult.okPage(meshInfos, result.getTotal());
    }

    public void dissolutionUser(Integer meshId, Integer userId) {
        if (Objects.isNull(meshId) || Objects.isNull(userId)) {
            throw new BaseBusinessException(ServiceErrorEnum.PARAMETER_IS_EMPTY);
        }
        UserInfo loginUser = getLoginUser();
        Boolean isAdmin = loginUser.getIsAdmin();
        if (!isAdmin) {
            throw new BaseBusinessException(ServiceErrorEnum.NOT_ADMIN);
        }
        this.meshUserLinkMapper.deleteByMeshIdAndUserId(meshId, userId);
    }

    public void signOutUser(Integer meshId, Integer userId) {
        if (meshId == null || userId == null) {
            throw new BaseBusinessException(ServiceErrorEnum.PARAMETER_IS_EMPTY);
        }
        MeshInfo meshInfo = super.mapper.selectByPrimaryKey(meshId);
        if(meshInfo.getAdminId().equals(userId)){
            throw new BaseBusinessException(ServiceErrorEnum.SIGN_OUT_FAIL);
        }
        this.meshUserLinkMapper.deleteByMeshIdAndUserId(meshId, userId);
    }

    public void transferMesh(Integer meshId, Integer userId, Integer id){
        MeshInfo meshInfo = this.mapper.selectByPrimaryKey(meshId);
        UserInfo userInfo = this.userMapper.selectByPrimaryKey(id);
        if(null == meshInfo){
            throw new BaseBusinessException(ServiceErrorEnum.NOTFUND_MESH);
        }else{
            if(!userId.equals(meshInfo.getAdminId())){
                throw new BaseBusinessException(ServiceErrorEnum.MESH_NOT_ADMINISTRATOR);
            }
            if(id.equals(userId)){
                throw new BaseBusinessException(ServiceErrorEnum.MESH_ADMINISTRATOR);
            }
        }
        if(null == userInfo){
            throw new BaseBusinessException(ServiceErrorEnum.NOTFUND_USER);
        }else{
            meshInfo.setAdminId(userInfo.getId());
            meshInfo.setUserName(userInfo.getUsername());
            meshInfo.setNickname(userInfo.getNickname());
            this.mapper.updateByPrimaryKeySelective(meshInfo);
        }
    }
}
